#include "Node.h"

#include "Player.h"
#include <MessageHandler.h>
#include <algorithm>
#include <iostream>
#include <iomanip>
#include "Game.h"

void Node::update(float dt)
{
	//need to fill it in with diferent states for animations
	//eg. neutral can at the same time be hacked and secured

	anims->update(dt);

	//loop throug all connections and send message to start hacking if connection time is less than 0
	std::hash_map<Node*, float>::iterator itterConnection= connections.begin();
	while (itterConnection != connections.end()) {
		
		float tmpTime = this->getConnectionTime(itterConnection->first);
		tmpTime = tmpTime - dt;
		
		if(tmpTime <= 0)
		{
			//ready to performe action
			if(this->getNodeState() == nodeOwner::PLAYER || this->getHackingState() == hackedState::HACKING )
			{
				Message message(itterConnection->first, "Hacking", 0);
				MessageHandler::sendMessage(message);
			}
			
			if(this->getNodeState() == nodeOwner::ENEMY || this->getSecuringState() == secureState::SECURING )
			{
				Message message(itterConnection->first, "Securing", 0);
				MessageHandler::sendMessage(message);
			}
			//set connection time to default
			this->setConnectionTime(itterConnection->first, itterConnection->first->getDistance());
		}
		else
			this->setConnectionTime(itterConnection->first, tmpTime);
	}


	if(this->hacking == hackedState::HACKING && (this->securing == secureState::SECURED || 
												 this->securing == secureState::NOTSECURED))
	{
		hackingTimeleft = hackingTimeleft - dt;
		if (owner == Node::NEUTRAL)
			anims->playAnimation("hackingNeutralNodeAnim");
		if (owner == Node::FINISH)
			anims->playAnimation("hackingFinishBaseAnim");
		if(hackingTimeleft <= 0)
		{
			if(this->stillMoney)
			{
				level++;
				hackingTimeleft = level;
				securingTimeleft = level;
				this->securing == secureState::NOTSECURED;

				//need to send message to player to let him update chacking chain
				std::list<Entity*>* playersList = EntityManager::getNamedEntities("Player");
				std::list<Entity*>::iterator iter = playersList->begin();
				while(iter != playersList->end()){
			
					Message message2((Player*)*iter, "EarnMoney", this);
					MessageHandler::sendMessage(message2);
			
					iter++;

				}
				stillMoney = false;
			} 

			Message message(this, "Hacked", 0);
			MessageHandler::sendMessage(message);
			if (owner == Node::NEUTRAL)
				anims->playAnimation("hackedNodeAnim");
			if (owner == Node::FINISH)
				anims->playAnimation("hackedFinishBaseAnim");
		}
	}

	if(this->hacking == hackedState::HACKED)
	{
		
		//need to send message to player to let him update chacking chain
		std::list<Entity*>* playersList = EntityManager::getNamedEntities("Player");
		std::list<Entity*>::iterator iter = playersList->begin();
		while(iter != playersList->end()){
		//we need to send message to player that will tell him to clear chain
			Message message((Player*)*iter, "NodeHacked", this);
			MessageHandler::sendMessage(message);
			

			Message message2((Player*)*iter, "EarnMoney", this);
			MessageHandler::sendMessage(message2);
			
			iter++;

		}
	}


	if(this->securing == secureState::SECURING && ((this->hacking == hackedState::HACKED)||
													this->hacking == hackedState::NOTHACKED))
	{
		securingTimeleft = securingTimeleft - dt;
		if (owner == Node::NEUTRAL)
			anims->playAnimation("securingNeutralNodeAnim");
		if (owner == Node::FINISH)
			anims->playAnimation("securingFinishBaseAnim");
		if(securingTimeleft <= 0)
		{
			if(!this->stillMoney)
			{
				level++;
				hackingTimeleft = level;
				securingTimeleft = level;
				this->hacking == hackedState::NOTHACKED;

				//need to send message to player to let him update chacking chain
				std::list<Entity*>* playersList = EntityManager::getNamedEntities("Player");
				std::list<Entity*>::iterator iter = playersList->begin();
				while(iter != playersList->end()){
			
					Message message2((Player*)*iter, "LoseMoney", this);
					MessageHandler::sendMessage(message2);
			
					iter++;

				}
				stillMoney = true;
			} 

			Message message(this, "Secured", 0);
			MessageHandler::sendMessage(message);
			if (owner == Node::NEUTRAL)
				anims->playAnimation("securedNodeAnim");
			if (owner == Node::FINISH)
				anims->playAnimation("securedFinishBaseAnim");
		}
	}

	if(this->securing == secureState::SECURED)
	{

		//need to send message to enemy to let him update secured chain
		std::list<Entity*>* enemyList = EntityManager::getNamedEntities("Enemy");
		std::list<Entity*>::iterator iter = enemyList->begin();
		while(iter != enemyList->end()){
			//we need to send message to player that will tell him to clear chain
			Message message((Enemy*)*iter, "NodeSecured", this);
			MessageHandler::sendMessage(message);
			iter++;
		}
	}
}

void Node::draw(ID3DXSprite* sprite)
{
	//First we work out the centre of the frame
	D3DXVECTOR2 centre;
	centre.x = (float)(anims->getCurrentAnimation()->getFrameWidth() / 2);
	centre.y = (float)(anims->getCurrentAnimation()->getFrameHeight() / 2);

	/* Now we create a transformation matrix. If flipped, we scale X by -1
	 * we also use the position vector in our transaction */
	D3DXMATRIX mat;
	D3DXMatrixTransformation2D(&mat, 0, 0, 0, 0, 0,
			   &D3DXVECTOR2(position.x, position.y));

	//Now we use this transformation to draw with, we set the draw position to 0 to avoid issues
	
	anims->draw(sprite, D3DXVECTOR3(0, 0, 0), mat);
}



void Node::addConnectedNodes(std::list<Node*>* newList) 
{ 
	if(connectedNodes.size() == 0)
	{
		//if list is empty
		connectedNodes = *newList;
	}else 
	{
		//for each element in new list
		std::list<Node*>::iterator itterNewList = newList->begin();
		while (itterNewList != newList->end()) {
			//find out if there is that element in current list already
			std::list<Node*>::iterator elementItter = std::find(this->connectedNodes.begin(), this->connectedNodes.end(), *itterNewList); 

			//if element not found
			if(elementItter == this->connectedNodes.end())
			{
				//add it!!
				this->connectedNodes.push_back((*elementItter));
				setConnectionTime((*elementItter), this->getDistance());

			}

			itterNewList++;
		}
	}
}

void Node::addConnectedNode(Node* newNode) {
	//find element in list
	std::list<Node*>::iterator elementItter = std::find(this->connectedNodes.begin(), this->connectedNodes.end(), newNode); 
	//if element not found
	if(elementItter == this->connectedNodes.end())
	{
		//add it!!
		this->connectedNodes.push_back((*elementItter));
	}

}

void Node::clearNodes() {
	std::list<Node*>::iterator itterConnectedNodes = connectedNodes.begin();
	while (itterConnectedNodes != connectedNodes.end()) {
		delete  *itterConnectedNodes;
		*itterConnectedNodes = 0;
	}
	connectedNodes.clear();

}

void Node::handleMessage(Message message)
{
	// Handle message code goes here....
	if (message.message == "Hacking")
	{
		this->hacking = hackedState::HACKING; 
		// Add play animation
	}
	else if(message.message == "Hacked")
	{
		this->hacking = hackedState::HACKED;
		Game* gameInstance = (Game*)game;
		if (owner == Node::FINISH /*|| owner == Node::ENEMY*/ )


			gameInstance->stateMachine.changeState("Win");
	}

	if(message.message == "Securing")
	{
		this->securing = secureState::SECURING;
	}
	else if(message.message == "Secured")
	{
		this->securing = secureState::SECURED;
		Game* gameInstance = (Game*)game;
		if (owner == Node::FINISH /*|| owner == Node::PLAYER*/)
			gameInstance->stateMachine.changeState("Lose");
	}
}